package com.itheima.orm.utils;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.itheima.core.DmlSqlType;

public class JdbcUtil {
	static{
		registDriverClass();
		if(PropertiesConstans.createTable){
			crateTable();
		}
	}
	
	//注入jdbc驱动
	private static void registDriverClass(){
		try {
			Class.forName(PropertiesConstans.jdbcDriverClassName);
		} catch (ClassNotFoundException e) {
			System.err.println("注入jdbc驱动失败！");
			e.printStackTrace();
		}
	}
	
	//自动创建表
	private static void crateTable(){
		try {
			Connection connection = getConnection();
			Statement statement = connection.createStatement();
			List<String> classNames = PropertiesConstans.classNames;
			for (String className : classNames) {
				String ddlSql = buildDDLSql(className);
				statement.addBatch(ddlSql);
			}
			statement.executeBatch();
			statement.clearBatch();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	//java数据类型转数据库数据类型
	private static String java2DatabaseTypeConverter(String javaType){
		switch(javaType){
		case "String":return "varchar(255)";
		case "Date":return "date";
		case "int":return "int(255)";
		case "Integer":return "int(255)";
		case "double":return "double(5,2)";
		case "Double":return "double(5,2)";
		case "boolean":return "tinyint(1)";
		case "Boolean":return "tinyint(1)";
		case "float":return "float(5,2)";
		case "Float":return "float(5,2)";
		case "long":return "int(255)";
		case "Long":return "int(255)";
		case "short":return "int(255)";
		case "Short":return "int(255)";
		case "byte":return "blob";
		case "Byte":return "blob";
		default: return null;
		}
	}
	
	
	
	//获取jdbc连接
	public static Connection getConnection(){
		try {
			return DriverManager.getConnection(PropertiesConstans.jdbcUrl, PropertiesConstans.jdbcUser, PropertiesConstans.jdbcPassword);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	//构建sql  dml
	public static String buildDMLSql(String className,DmlSqlType dmlSqlType){
		Map<String, String> fieldsAndTypes = ReflectUtil.getFieldsAndTypes(className);
		Set<String> keySet = fieldsAndTypes.keySet();
		String tableName = ReflectUtil.getClassName(className);
		StringBuffer sql = new StringBuffer();
		if(dmlSqlType == DmlSqlType.INSERT){
			//insert into student(id,name,address) values(?,?,?)
			sql.append("insert into "+tableName+"(");
			for (String key : keySet) {
				sql.append(key+",");
			}
			sql.setLength(sql.length()-1);
			sql.append(") values(");
			for(int i=0;i<keySet.size();i++){
				sql.append("?,");
			}
			sql.setLength(sql.length()-1);
			sql.append(")");
		}else if(dmlSqlType == DmlSqlType.UPDATE){
			//key value  name jack
			//update student set id=?,name=?,address=? where id = ?
			sql.append("update "+tableName+" set ");
			for (String key : keySet) {
				sql.append(key+"=?,");
			}
			sql.setLength(sql.length()-1);
			sql.append(" where id=?");
		}else if(dmlSqlType == DmlSqlType.DELETE){
			
		}else if(dmlSqlType == DmlSqlType.SELECT){
			
		}
		return sql.toString();
	} 
	
	
	
	//构建sql  ddl
	private static String buildDDLSql(String className){
		Map<String, String> fieldsAndTypes = ReflectUtil.getFieldsAndTypes(className);
		String idType = fieldsAndTypes.get("id");
		if(null==idType || "".equals(idType)){
			throw new RuntimeException(className+":这个类没有id属性。。。。。require");
		}
		String ddlSql = "create table if not exists `"+ReflectUtil.getClassName(className)+"`(";
		Set<String> keySet = fieldsAndTypes.keySet();
		for (String key : keySet) {
			if("id".equals(key) && ("int".equals(fieldsAndTypes.get(key))||"Integer".equals(fieldsAndTypes.get(key)))){
				//是id就自增长
				ddlSql = ddlSql.concat(key+" "+java2DatabaseTypeConverter(fieldsAndTypes.get(key))+" "+"primary key auto_increment,");
			}else if("id".equals(key)){
				ddlSql = ddlSql.concat(key+" "+java2DatabaseTypeConverter(fieldsAndTypes.get(key))+" "+"primary key,");
			}else{
				ddlSql = ddlSql.concat(key+" "+java2DatabaseTypeConverter(fieldsAndTypes.get(key))+",");
			}
		}
		ddlSql = ddlSql.substring(0, ddlSql.length()-1);
		ddlSql = ddlSql.concat(")");
		return ddlSql;
	}
	
	
	//执行sql
	public static void executeSql(Connection connection,Object obj,String sql,DmlSqlType dmlSqlType){
		PreparedStatement statement = null;
		try {
			Class<? extends Object> clazz = obj.getClass();
			Map<String, String> fieldsAndTypes = ReflectUtil.getFieldsAndTypes(clazz.getName());
			Set<String> keySet = fieldsAndTypes.keySet();
			if(dmlSqlType == DmlSqlType.INSERT){
				statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
				for (int i=0;i<keySet.size();i++) {
					String key = (String) keySet.toArray()[i];
					Method method = clazz.getMethod("get"+String.valueOf(key.charAt(0)).toUpperCase()+key.substring(1));
					Object value = method.invoke(obj);
					statement.setObject(i+1, value);
				}
				statement.executeUpdate();
			}else{
				//update student set id=?,name=?,address=? where id = ?
				statement = connection.prepareStatement(sql);
				Method getIdMethod = clazz.getMethod("getId");
				Object idValue = getIdMethod.invoke(obj);
				if(null==idValue){
					throw new RuntimeException(obj+"更新这个类的对象id未赋值");
				}
				for (int i=0;i<keySet.size();i++) {
					String key = (String) keySet.toArray()[i];
					Method method = clazz.getMethod("get"+String.valueOf(key.charAt(0)).toUpperCase()+key.substring(1));
					Object value = method.invoke(obj);
					statement.setObject(i+1, value);
				}
				statement.setObject(keySet.size()+1, idValue);
				statement.executeUpdate();
			}
			
			if(dmlSqlType == DmlSqlType.INSERT){
				ResultSet generatedKeys = statement.getGeneratedKeys();
				while(generatedKeys.next()){
					int key = generatedKeys.getInt(1);
//					Method method = clazz.getMethod("setId",Integer.class);  Integer.class与int.class不同
					Method[] declaredMethods = clazz.getDeclaredMethods();
					for (Method method : declaredMethods) {
						if("setId".equals(method.getName())){
							method.invoke(obj, key);
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			release(null, statement, connection);
		}
	}
	
	//释放jdbc资源
	public static void release(ResultSet resultSet,Statement statement,Connection connection){
		if(null!=resultSet){
			try {
				resultSet.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		if(null!=statement){
			try {
				statement.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
		if(null!=connection){
			try {
				connection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
}
